<template>
  <div 
    :class="[
      'bx-input-number',
      'bx-glass',
      {
        'bx-input-number--disabled': disabled,
        'bx-input-number--readonly': readonly,
        [`bx-input-number--${size}`]: size
      }
    ]"
  >
    <div class="bx-input-number__controls">
      <button
        :class="[
          'bx-input-number__control',
          'bx-input-number__control--up'
        ]"
        :disabled="disabled || isMaxDisabled"
        @click="handleIncrease"
        @mousedown="handleMouseDown('increase')"
        @mouseup="handleMouseUp"
        @mouseleave="handleMouseUp"
      >
        <BxIcon name="chevron-up" />
      </button>
      
      <button
        :class="[
          'bx-input-number__control',
          'bx-input-number__control--down'
        ]"
        :disabled="disabled || isMinDisabled"
        @click="handleDecrease"
        @mousedown="handleMouseDown('decrease')"
        @mouseup="handleMouseUp"
        @mouseleave="handleMouseUp"
      >
        <BxIcon name="chevron-down" />
      </button>
    </div>

    <input
      ref="inputRef"
      v-model="displayValue"
      type="text"
      :placeholder="placeholder"
      :disabled="disabled"
      :readonly="readonly"
      class="bx-input-number__input"
      @focus="handleFocus"
      @blur="handleBlur"
      @input="handleInput"
      @keydown="handleKeydown"
    />
  </div>
</template>

<script>
import { ref, computed, watch, nextTick } from 'vue'
import BxIcon from '../basic/BxIcon.vue'

export default {
  name: 'BxInputNumber',
  components: {
    BxIcon
  },
  props: {
    modelValue: {
      type: Number,
      default: undefined
    },
    min: {
      type: Number,
      default: -Infinity
    },
    max: {
      type: Number,
      default: Infinity
    },
    step: {
      type: Number,
      default: 1
    },
    precision: {
      type: Number,
      default: undefined
    },
    placeholder: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    },
    readonly: {
      type: Boolean,
      default: false
    },
    size: {
      type: String,
      default: 'medium',
      validator: (value) => ['small', 'medium', 'large'].includes(value)
    },
    formatter: {
      type: Function,
      default: undefined
    },
    parser: {
      type: Function,
      default: undefined
    }
  },
  emits: ['update:modelValue', 'change', 'focus', 'blur'],
  setup(props, { emit }) {
    const inputRef = ref(null)
    const displayValue = ref('')
    const focused = ref(false)
    const pressTimer = ref(null)

    const currentValue = computed(() => {
      return props.modelValue
    })

    const isMinDisabled = computed(() => {
      return currentValue.value !== undefined && currentValue.value <= props.min
    })

    const isMaxDisabled = computed(() => {
      return currentValue.value !== undefined && currentValue.value >= props.max
    })

    const formatNumber = (num) => {
      if (num === undefined || num === null || isNaN(num)) return ''
      
      let formatted = num
      
      // 应用精度
      if (props.precision !== undefined) {
        formatted = Number(num.toFixed(props.precision))
      }
      
      // 应用自定义格式化器
      if (props.formatter) {
        return props.formatter(formatted)
      }
      
      return String(formatted)
    }

    const parseNumber = (str) => {
      if (!str) return undefined
      
      let parsed = str
      
      // 应用自定义解析器
      if (props.parser) {
        parsed = props.parser(str)
      }
      
      const num = Number(parsed)
      return isNaN(num) ? undefined : num
    }

    const clampValue = (value) => {
      if (value === undefined || value === null) return undefined
      
      let clamped = Math.max(props.min, Math.min(props.max, value))
      
      if (props.precision !== undefined) {
        clamped = Number(clamped.toFixed(props.precision))
      }
      
      return clamped
    }

    const updateValue = (value) => {
      const clampedValue = clampValue(value)
      
      if (clampedValue !== currentValue.value) {
        emit('update:modelValue', clampedValue)
        emit('change', clampedValue)
      }
      
      // 更新显示值
      if (!focused.value) {
        displayValue.value = formatNumber(clampedValue)
      }
    }

    const handleIncrease = () => {
      const current = currentValue.value || 0
      const newValue = current + props.step
      updateValue(newValue)
    }

    const handleDecrease = () => {
      const current = currentValue.value || 0
      const newValue = current - props.step
      updateValue(newValue)
    }

    const handleMouseDown = (action) => {
      if (props.disabled || props.readonly) return
      
      const handler = action === 'increase' ? handleIncrease : handleDecrease
      
      // 立即执行一次
      handler()
      
      // 设置重复执行
      pressTimer.value = setTimeout(() => {
        const interval = setInterval(handler, 100)
        pressTimer.value = interval
      }, 600)
    }

    const handleMouseUp = () => {
      if (pressTimer.value) {
        clearTimeout(pressTimer.value)
        clearInterval(pressTimer.value)
        pressTimer.value = null
      }
    }

    const handleFocus = (event) => {
      focused.value = true
      displayValue.value = currentValue.value !== undefined ? String(currentValue.value) : ''
      emit('focus', event)
    }

    const handleBlur = (event) => {
      focused.value = false
      
      const parsedValue = parseNumber(displayValue.value)
      updateValue(parsedValue)
      
      emit('blur', event)
    }

    const handleInput = (event) => {
      displayValue.value = event.target.value
    }

    const handleKeydown = (event) => {
      if (props.disabled || props.readonly) return
      
      switch (event.key) {
        case 'ArrowUp':
          event.preventDefault()
          handleIncrease()
          break
        case 'ArrowDown':
          event.preventDefault()
          handleDecrease()
          break
        case 'Enter':
          event.preventDefault()
          inputRef.value?.blur()
          break
      }
    }

    const focus = () => {
      inputRef.value?.focus()
    }

    const blur = () => {
      inputRef.value?.blur()
    }

    // 监听值变化
    watch(() => props.modelValue, (newVal) => {
      if (!focused.value) {
        displayValue.value = formatNumber(newVal)
      }
    }, { immediate: true })

    return {
      inputRef,
      displayValue,
      isMinDisabled,
      isMaxDisabled,
      handleIncrease,
      handleDecrease,
      handleMouseDown,
      handleMouseUp,
      handleFocus,
      handleBlur,
      handleInput,
      handleKeydown,
      focus,
      blur
    }
  }
}
</script>

<style scoped>
.bx-input-number {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 120px;
  border: 1px solid var(--bx-glass-border);
  border-radius: var(--bx-radius-medium);
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
  transition: all var(--bx-transition-medium);
  font-family: var(--bx-font-family);
}

.bx-input-number:hover {
  border-color: var(--bx-glass-border-hover);
  background: var(--bx-glass-bg-hover);
}

.bx-input-number:focus-within {
  border-color: rgba(0, 122, 255, 0.5);
  box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.1);
}

.bx-input-number--disabled {
  opacity: 0.6;
  cursor: not-allowed;
  background: rgba(255, 255, 255, 0.03);
}

.bx-input-number--small {
  width: 100px;
  font-size: 13px;
}

.bx-input-number--large {
  width: 140px;
  font-size: 16px;
}

.bx-input-number__input {
  flex: 1;
  width: 0;
  padding: 8px 12px;
  border: none;
  outline: none;
  background: transparent;
  color: var(--bx-text-primary);
  font-size: inherit;
  font-family: inherit;
  text-align: center;
}

.bx-input-number--small .bx-input-number__input {
  padding: 6px 8px;
}

.bx-input-number--large .bx-input-number__input {
  padding: 12px 16px;
}

.bx-input-number__input::placeholder {
  color: var(--bx-text-tertiary);
}

.bx-input-number__input:disabled {
  cursor: not-allowed;
}

.bx-input-number__controls {
  position: absolute;
  right: 1px;
  top: 1px;
  bottom: 1px;
  display: flex;
  flex-direction: column;
  width: 24px;
  border-radius: 0 var(--bx-radius-medium) var(--bx-radius-medium) 0;
  overflow: hidden;
}

.bx-input-number--small .bx-input-number__controls {
  width: 20px;
}

.bx-input-number--large .bx-input-number__controls {
  width: 28px;
}

.bx-input-number__control {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
  color: var(--bx-text-secondary);
  cursor: pointer;
  transition: all var(--bx-transition-medium);
  font-size: 10px;
}

.bx-input-number__control:hover:not(:disabled) {
  background: var(--bx-glass-bg-hover);
  color: var(--bx-text-primary);
}

.bx-input-number__control:active:not(:disabled) {
  background: rgba(0, 122, 255, 0.1);
}

.bx-input-number__control:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.bx-input-number__control--up {
  border-bottom: 1px solid var(--bx-glass-border);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .bx-input-number {
    width: 100px;
  }
  
  .bx-input-number--small {
    width: 80px;
  }
  
  .bx-input-number--large {
    width: 120px;
  }
  
  .bx-input-number__controls {
    width: 20px;
  }
}
</style>

